Python高级(进程、线程和协程)

您所在的位置:网站首页 python 自动运行程序 Python高级(进程、线程和协程)

Python高级(进程、线程和协程)

#Python高级(进程、线程和协程) | 来源: 网络整理| 查看: 265

​ 进程:运行中的程序. 每次我们执行一个程序, 咱们的操作系统对自动的为这个程序准备一些必要的资源(例如,分配内存,创建一个能够执行的线程。)

​ 线程:程序内,可以直接被CPU调度的执行过程. 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

进程与线程之间的关系:

​ 进程是资源单位(公司),线程是执行单位(员工),就好比是一家公司,一家公司的资源就是桌椅板凳,电脑饮水机这些资源,但是,我们如果说一家公司正在运转着,运行着,那里面必须要有能为这家公司工作的人。程序里面也一样,进程就是为了程序运行而需要的各种资源。但是程序想要运行,就必须由线程来被CPU调度执行。

​ 我们运行的每一个程序默认都会有一个线程,哪怕是只有helloworld级别的程序,想要执行,也会有一个线程产生。

线程

​ 顾名思义,多线程就是让程序产生多个线程一起去执行。 还拿公司举例子,一家公司里如果只有一个员工,工作效率肯定不会高到哪里去,怎么提高效率?多招点儿人就OK了。

直接使用Thread创建线程

单线程

1234567def work(): for i in range(1000): print("func", i)if __name__ == '__main__': work()

多线程

12345678910111213import threading# 类似于同一个公司开设不同的部门# 或者同一个部门有多个小组def work(): for i in range(1000): print(f"{threading.current_thread().name} Print: {i}") # 打印当前线程名称if __name__ == '__main__': for i in range(10): t = threading.Thread(target=work, name=f"threadP{i}") # 设置线程名称 t.start() 线程池

python还提供了线程池功能,可以一次性的创建多个线程,并且,不需要我们程序员手动去维护。一切都交给线程池来自动管理。

12345678910from concurrent.futures.thread import ThreadPoolExecutordef work(name): for i in range(10000): print(f'{name}:{i}')with ThreadPoolExecutor(16) as t: # 设置线程池,大小一般为CPU核心数的2倍,这里设置的最大线程数为16 for i in range(4): t.submit(work, f'线程{i}') 进程

一个公司能创造的价值毕竟是有限的,怎么办?开分公司啊.,此所谓多进程,python实现多进程的方案和多线程几乎一样,非常的简单。

1234567891011121314from multiprocessing import Process# 一个公司能创造的价值毕竟是有限的. 怎么办?# 开分公司啊. 此所谓多进程. python实现多进程的方案和多线程几乎一样. 非常的简单def func(): for i in range(1000): print("func", i)if __name__ == '__main__': p = Process(target=func) p.start() for i in range(1000): print("main", i) 协程

​ 协程是我要重点去讲解的一个知识点,它能够更加高效的利用CPU。

​ 其实, 我们能够高效的利用多线程来完成爬虫其实已经很6了,但是,从某种角度讲,线程的执行效率真的就无敌了么?我们真的充分的利用CPU资源了么?非也~ 比如,我们来看下面这个例子。

我们单独的用一个线程来完成某一个操作,看看它的效率是否真的能把CPU完全利用起来。

12345678import timedef func(): print("我爱黎明") time.sleep(3) print("我真的爱黎明") func()

​ 各位请看,在该程序中,我们的func()实际在执行的时候至少需要3秒的时间来完成操作,中间的三秒钟需要让我当前的线程处于阻塞状态。阻塞状态的线程 CPU是不会来执行你的,那么此时cpu很可能会切换到其他程序上去执行。此时,对于你来说,CPU其实并没有为你工作(在这三秒内),那么我们能不能通过某种手段,让CPU一直为我而工作,尽量的不要去管其他人。

​ 我们要知道CPU一般抛开执行周期不谈,如果一个线程遇到了IO操作,CPU就会自动的切换到其他线程进行执行。那么,如果我想办法让我的线程遇到了IO操作就挂起,留下的都是运算操作,那CPU是不是就会长时间的来照顾我。

​ 以此为目的,伟大的程序员就发明了一个新的执行过程。当线程中遇到了IO操作的时候,将线程中的任务进行切换,切换到其他任务。等原来的IO执行完了,再恢复回原来的任务中。

image-20210308154852699

就形成了这样一种模型,在程序遇到了IO操作(费时不费力的操作)时,自动切换到其他任务,该模型被称为协程。

协程基本使用

需要使用关键词async和await。

async是定义一个异步函数的关键字,异步函数是协程的一种。它用于定义一个可以在执行过程中挂起的函数,该函数可以在遇到await关键字时挂起,并等待另一个协程执行完毕后再继续执行。 await则是用于挂起当前协程并等待另一个协程执行完毕的关键字。当遇到await关键字时,当前协程将会暂停执行,直到等待的协程执行完毕,并返回结果后才会继续执行。 async/await的使用可以大大简化异步编程的复杂性,使得在Python中实现高效的异步程序变得更加容易。通过使用async/await,我们可以将一些常见的异步操作抽象为协程,从而使得我们可以使用类似于同步代码的方式来实现异步操作。 12345678910111213141516171819202122232425262728293031323334import timeimport asyncio# await: 当该任务被挂起后, CPU会自动切换到其他任务中async def func1(): print("func1, start") await asyncio.sleep(3) print("func1, end")async def func2(): print("func2, start") await asyncio.sleep(4) print("func2, end")async def func3(): print("func3, start") await asyncio.sleep(2) print("func3, end")async def run(): start = time.time() tasks = [ # 协程任务列表 asyncio.create_task(func1()), # create_task创建协程任务 asyncio.create_task(func2()), asyncio.create_task(func3()), ] await asyncio.wait(tasks) # 等待所有任务执行结束 print(time.time() - start)if __name__ == '__main__': asyncio.run(run()) 协程异步IO操作

协程可以结合相关异步的第三方库,达到异步网页请求和文件操作操作,最大化使用CPU资源。

aiohttp:异步HTTP请求库,类似于requests库。 aiofiles:异步文件操作库,一般用于文件读写。 1234567891011121314151617181920212223242526272829303132333435363738394041424344import aiohttpimport asyncioimport aiofilesasync def download(url): try: name = url.split("/")[-1].split('@')[0] # 创建session对象 -> 相当于requsts对象 async with aiohttp.ClientSession() as session: # 发送请求, 这里和requests.get()几乎没区别, 除了代理换成了proxy async with session.get(url, ssl=False) as resp: # 取消SSL验证 # # resp.text(encoding='') 这可以设置字符集 # 读取数据. 如果想要读取源代码. 直接resp.text()即可. 比原来多了个() content = await resp.content.read() # 写入文件, 用默认的open也OK. 用aiofiles能进一步提升效率 async with aiofiles.open('../download_files/' + name, mode="wb") as f: await f.write(content) return "OK" except Exception as e: print(e) return "NO"async def main(): url_list = [ "https://cdn-usa.skypixel.com/uploads/usa_files/storynode/image/214c3e7a-767d-41b3-9dcc-c43df9b2e5fd.jpg@!1200", "https://cdn-usa.skypixel.com/uploads/usa_files/storynode/image/4b32f894-a8e0-4d92-9dc7-f9c5b932723f.JPG@!1200" ] tasks = [] for url in url_list: # 创建任务 task = asyncio.create_task(download(url)) tasks.append(task) await asyncio.wait(tasks)if __name__ == '__main__': # asyncio.run(main()) 用这句话会报错RuntimeError: Event loop is closed loop = asyncio.get_event_loop() loop.run_until_complete(main())


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3